﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using Microsoft.Win32;
using System.Windows;
using System.Xml;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Controls;
using System.IO;
using SHomeWorkshop.LunarConcept.Converters;
using SHomeWorkshop.LunarConcept.Controls;

namespace SHomeWorkshop.LunarConcept.Commands
{
    /// <summary>
    /// 创建时间：2012年1月30日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：将当前页面导出为图像文件。
    /// ★①，修改类名。
    /// </summary>
    public static class OutportMainPageToImageFileCommand
    {

        #region 构造方法=====================================================================================================

        /// <summary>
        /// ★②，修改静态构造方法名。
        /// </summary>
        static OutportMainPageToImageFileCommand()//类型构造器
        {
            //★③，修改两个字符串参数名。★④以及第三个参数的类型名。
            routedUICmd = new RoutedUICommand(
                "OutportMainPageToImageFileCommand",
                "OutportMainPageToImageFileCommand",
                typeof(OutportMainPageToImageFileCommand),//创建RoutedUICommand对象
                null//不需要快捷键
                );

            cmdBinding.Command = routedUICmd;
            cmdBinding.CanExecute += new CanExecuteRoutedEventHandler(cmdBinding_CanExecute);
            cmdBinding.Executed += new ExecutedRoutedEventHandler(cmdBinding_Executed);
        }

        #endregion

        #region 字段与属性===================================================================================================

        private static CommandBinding cmdBinding = new CommandBinding();
        /// <summary>
        /// 用在主窗口CommandBindings集合中的命令绑定。
        /// 
        /// 它的Command是RoutedUICommand。
        /// ——因此，RoutedUICommand是否可以运行将由CmdBinding的CanExecute事件决定。
        /// ——而且，RoutedUICommand的执行也是通过CmdBinding的Execute事件来进行的。
        /// </summary>
        public static CommandBinding CmdBinding
        {
            get { return cmdBinding; }
        }

        private static RoutedUICommand routedUICmd;//创建私有字段
        /// <summary>
        /// [只读静态属性]表示在WPF系统中注册的一个RoutedUICommand。
        /// ——必须和CommandBinding配合才能使用。
        ///     CommandBinding要添加到主窗口的CommandBindings集合中；
        ///     RoutedUICommand则要向WPF系统注册。
        ///     
        /// ★说明：使用静态属性是因为这样在Xaml代码中比较便于绑定。
        /// </summary>
        public static RoutedUICommand RoutedUICmd//创建只读静态属性
        {
            get { return routedUICmd; }
        }

        #endregion


        #region 方法=========================================================================================================



        static void cmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            //★⑧，修改此方法的实现。


            //考虑到性能问题，全部取消此判断。反正执行时会判断。
            //if (Globals.MainWindow.EditorManager.GetMainSelectedPageEditor() == null)
            //{
            //    e.CanExecute = false; return;
            //}

            e.CanExecute = true;
        }

        static void cmdBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            //★⑦，修改此方法的实现。

            LunarMessage.Warning(Execute());
        }

        /// <summary>
        /// [公开静态方法]即使此命令处于禁用状态，也可以通过代码调用此方法来执行特定任务！！！
        /// 
        /// 当被绑定的命令被调用（触发）时，会引发cmdBinding_Executed事件。
        /// 在cmdBinding_Executed事件处理器方法中已添加了调用Execute()方法的代码。
        /// 
        /// ——因此，触发命令，就相当于调用此方法！！！
        /// </summary>
        internal static string Execute(string fileFullPath = null)
        {
            if (Globals.MainWindow == null) return "　　未找到Globals.MainWindow。";

            EditorManager manager = Globals.MainWindow.EditorManager;

            if (manager == null) return "　　未找到页面管理器。";

            PageEditor mainPageEditor = manager.GetMainSelectedPageEditor();
            if (mainPageEditor == null) return "　　未找到活动页面。";

            double scale = ScaleValueConverter.GetNewScaleValue(Globals.MainWindow.SliderOfScale.Value);

            if (scale < 1)
            {
                MessageBoxResult r = MessageBox.Show("　　当前文档的缩放比例小于１，导出的图片文件可能比较模糊。要继续吗？",
                    Globals.AppName, MessageBoxButton.YesNo, MessageBoxImage.Warning);
                if (r != MessageBoxResult.Yes) return string.Empty;
            }

            string filename;

            if (fileFullPath == null)
            {
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.Title = Globals.AppName + "——导出图片：";
                sfd.Filter = "标记图像格式(*.tiff)|*.tiff|可移植网络图形(*.png)|*.png";
                sfd.FileName = Globals.MainWindow.EditorManager.DefaultShortFileName + "_页面图";

                if (sfd.ShowDialog() != true)
                {
                    Globals.MainWindow.MainScrollViewer.Focus();
                    return string.Empty;
                }

                filename = sfd.FileName;
            }
            else
            {
                filename = fileFullPath;
            }

            bool isPng = filename.EndsWith(".png");
            return OutputMainPageToImage(fileFullPath, manager, mainPageEditor, filename, isPng, scale);
        }

        public static string OutputMainPageToImage(string fileFullPath, EditorManager manager, PageEditor mainPageEditor, string filename, bool isPng, double scale, bool showResultMessage = true)
        {
            RenderTargetBitmap rtb = new RenderTargetBitmap(
                (int)(Globals.MainWindow.EditorManager.ActualWidth * scale) + 2,
                (int)(Globals.MainWindow.EditorManager.ActualHeight * scale) + 2,
                96, 96, PixelFormats.Pbgra32);

            if (isPng == false)
            {
                if (TextOptions.GetTextFormattingMode(Globals.MainWindow.MainScrollViewer) != TextFormattingMode.Ideal)
                {
                    MessageBoxResult msgBoxResult = MessageBox.Show("　　当前文档的显示方式为“锐利”，这适合屏幕显示，" +
                        "而不适合导出图片打印（文字会有锯齿）。\r\n" +
                        "　　您可以使用主界面“视图”功能区“文字渲染”组中两个按钮来在两种文字渲染方式间切换。\r\n\r\n" +
                        "　　真的要继续吗？",
                        Globals.AppName, MessageBoxButton.YesNo, MessageBoxImage.Warning);
                    if (msgBoxResult != MessageBoxResult.Yes) return string.Empty;
                }
            }

            try
            {
                //BitmapEncoder encoder = new PngBitmapEncoder();//分辨率只能是96DPI。
                //BitmapEncoder encoder = new GifBitmapEncoder();//分辨率过低。
                //BitmapEncoder encoder = new JpegBitmapEncoder();//分辨率可以是300DPI，但不支持透明底色。
                BitmapEncoder encoder;

                if (isPng)
                {
                    rtb = mainPageEditor.GetRenderTargetBitmap(false); ;//96DPI
                    encoder = new PngBitmapEncoder();
                }
                else
                {
                    rtb = mainPageEditor.GetRenderTargetBitmap();//300DPI
                    encoder = new TiffBitmapEncoder();
                }

                encoder.Frames.Add(BitmapFrame.Create(rtb));
                using (Stream stm = File.Create(filename))
                {
                    encoder.Save(stm);
                }

                // 透明底色并不好
                //if (manager.DocumentBackground is SolidColorBrush && File.Exists(filename))
                //{
                //    try
                //    {
                //        var bytes = GetTransparentArrayFromFileWithDelete(filename);
                //        using (FileStream fs = new FileStream(filename, FileMode.Create))
                //        {
                //            fs.Write(bytes, 0, bytes.Length);
                //        }
                //    }
                //    catch (Exception ex)
                //    {
                //        System.Windows.MessageBox.Show(ex.Message, Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Information);
                //    }
                //}

                if (isPng)
                {
                    using (StreamWriter sw = File.AppendText(filename))
                    {
                        sw.WriteLine();

                        sw.WriteLine(Globals.OutportImageSplitText);
                        sw.Write(Globals.MainWindow.EditorManager.XmlDocument.OuterXml);

                        //刷新“最近文档列表”。
                        RecentFileItem.WriteRecentFilesToXmlFile(filename);
                        RecentFileItem.ReadRecentFilesFromXmlFile();

                        if (fileFullPath == null)
                        {
                            if (showResultMessage)
                                System.Windows.MessageBox.Show("　　已导出为：" + filename +
                                    "\r\n\r\n　　导出为PNG格式的图片会嵌入文档数据，可以使用本程序重新打开此文档！\r\n" +
                                    "　　★★请勿使用图像编辑软件对导出的 PNG 图片进行编辑，这会破坏该图片文件尾部附加的文档数据。\r\n\r\n" +
                                    "　　★★Tiff格式的图片主要用以打印，【不支持】此功能！",
                                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Information);
                        }
                        else//非null是“Save()”方法调用。
                        {
                            MainWindow win = Globals.MainWindow;
                            win.EditorManager.IsModified = false;
                            win.EditorManager.ModifingItemsList.SynchronizeSavePoint();
                        }
                    }
                }
                else
                {
                    if(showResultMessage)
                        System.Windows.MessageBox.Show("　　已导出为：" + filename +
                                "\r\n\r\n　　★注意：导出为Tiff格式的图片【不会】嵌入文档数据，因此导出后【不能再用本程序打开】！",
                                Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Information);
                }

                return string.Empty;
            }
            catch (Exception ex)
            {
                return "导出为图像文件时出现异常。异常信息如下：\r\n　　"
                    + ex.Message + "\r\n　　" + ex.StackTrace;
            }
            finally
            {
                Globals.MainWindow.MainScrollViewer.Focus();
            }
        }

        /// <summary>
        /// 此方法仅适用于纯白背景的情况。
        /// 方法来自于：<https://www.codeproject.com/Questions/1090410/How-to-make-PNG-image-transparent>
        /// </summary>
        /// <param name="pathToFile"></param>
        /// <returns></returns>
        public static byte[] GetTransparentArrayFromFileWithDelete(string pathToFile)
        {
            byte[] newImage = new byte[0];
            var error = string.Empty;
            using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(pathToFile))
            {
                System.Drawing.Color pixel = bmp.GetPixel(0, 0);
                //if (pixel.A != 0)
                //{
                // Make backColor transparent for myBitmap.

                System.Drawing.Color transColor = System.Drawing.Color.Transparent;
                if (Globals.MainWindow.EditorManager.DocumentBackground is SolidColorBrush docBackBrush)
                {
                    transColor = System.Drawing.Color.FromArgb(docBackBrush.Color.A,
                                                         docBackBrush.Color.R,
                                                         docBackBrush.Color.G,
                                                         docBackBrush.Color.B);
                }
                bmp.MakeTransparent(transColor);

                System.Drawing.ImageConverter converter = new System.Drawing.ImageConverter();
                newImage = (byte[])converter.ConvertTo(bmp, typeof(byte[]));
                bmp.Dispose();
                //}
                //else
                //{
                //    FileStream fs = new FileStream(pathToFile, FileMode.OpenOrCreate, FileAccess.Read);
                //    newImage = new byte[fs.Length];
                //    fs.Read(newImage, 0, System.Convert.ToInt32(fs.Length));
                //    fs.Close();
                //}
            }

            try
            {
                File.Delete(pathToFile);
            }
            catch
            {
                return null;
            }
            return newImage;
        }
        #endregion
    }
}
